package cn.xinfei.xdecision.data.core.frame.executors.collect;


import cn.hutool.core.util.ObjectUtil;
import cn.xinfei.xdecision.common.model.datax.consts.VariableConst;
import cn.xinfei.xdecision.common.model.datax.datamanage.v2.Variable;
import cn.xinfei.xdecision.common.model.datax.enums.EnumUtil;
import cn.xinfei.xdecision.common.model.datax.enums.VariableTypeEnum;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

public class VariableHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(VariableHelper.class);

    public static Object getDefaultValue(Variable var) {
        String defaultValue = var.getVarDefaultValue();
        return ofValueType(var, defaultValue);
    }

    public static Object getDefaultNullValue(Variable var) {
        return ofNullValueType(var);
    }

    public static Object ofValueType(Variable var, String targetValue) {
        Object result;
        switch (EnumUtil.fromCodeOrThrow(VariableTypeEnum.class, String.valueOf(var.getVarValueType()))) {
            case INTEGER:
                result = Integer.valueOf(targetValue);
                break;
            case DOUBLE:
                result = Double.valueOf(targetValue);
                break;
            case BOOLEAN:
                result = Boolean.valueOf(targetValue);
                break;
            case STRING:
                result = targetValue;
                break;
            default:
                throw new IllegalArgumentException("未知变量类型");
        }
        return result;
    }
    public static Object ofNullValueType(Variable var) {
        Object result;
        switch (EnumUtil.fromCodeOrThrow(VariableTypeEnum.class, String.valueOf(var.getVarValueType()))) {
            case INTEGER:
                result = VariableConst.DEFAULT_NULL_INTEGER;
                break;
            case DOUBLE:
                result = VariableConst.DEFAULT_NULL_DUBLE;
                break;
            case BOOLEAN:
                result = Boolean.FALSE;
                break;
            case STRING:
                result = VariableConst.DEFAULT_NULL_STR;
                break;
            default:
                throw new IllegalArgumentException("未知变量类型");
        }
        return result;
    }

    public static Object toInterfaceRequestParam(Variable var, Object targetValue) {
        Object result;
        switch (EnumUtil.fromCodeOrThrow(VariableTypeEnum.class, String.valueOf(var.getVarValueType()))) {
            case INTEGER:
                result = targetValue;
                break;
            case DOUBLE:
                result = targetValue;
                break;
            case BOOLEAN:
                result = targetValue;
                break;
            case STRING:
                result = "\"" + targetValue + "\"";
                break;
            default:
                throw new IllegalArgumentException("未知变量类型");
        }
        return result;
    }

    public static Object getConstValue(Variable var) {
        String constValue = var.getConstValue();
        return ofValueType(var, constValue);
    }

    public static Object varTypeCheckIfNecessary(Variable var, Object obj) {
        Object object = null;
        if (ObjectUtil.isNull(var) || ObjectUtil.isNull(obj)) {
            return object;
        }
        switch (EnumUtil.fromCode(VariableTypeEnum.class, String.valueOf(var.getVarType()))) {
            case INTEGER:
                if (obj instanceof BigDecimal) {
                    BigDecimal result = (BigDecimal) obj;
                    object = result.intValue();
                } else if (obj instanceof Integer) {
                    object = obj;
                } else {
                    LOGGER.warn("变量计算结果和配置类型不匹配，变量信息：{},结果类型：{},结果值：{}", JSONObject.toJSONString(var), obj.getClass(), JSONObject.toJSONString(obj));
                    //赋予默认值
                    object = getDefaultValue(var);
                }
                break;
            case DOUBLE:
                if (obj instanceof BigDecimal) {
                    BigDecimal result = (BigDecimal) obj;
                    object = result.doubleValue();
                } else if (obj instanceof Double) {
                    object = obj;
                } else {
                    LOGGER.warn("变量计算结果和配置类型不匹配，变量信息：{},结果类型：{},结果值：{}", JSONObject.toJSONString(var), obj.getClass(), JSONObject.toJSONString(obj));
                    //赋予默认值
                    object = getDefaultValue(var);
                }
                break;
            case BOOLEAN:
                if (obj instanceof Boolean) {
                    object = obj;
                } else if (obj instanceof String) {
                    object = Boolean.valueOf(String.valueOf(obj));
                } else {
                    LOGGER.warn("变量计算结果和配置类型不匹配，变量信息：{},结果类型：{},结果值：{}", JSONObject.toJSONString(var), obj.getClass(), JSONObject.toJSONString(obj));
                    //赋予默认值
                    object = getDefaultValue(var);
                }
                break;
            case STRING:
                object = String.valueOf(obj);
                break;
            default:
                LOGGER.warn("计算结果转换，未知变量类型，变量信息：{}", JSONObject.toJSONString(var));
        }
        return object;
    }

    public static Map<String, Object> fillVarWithDefaultValueWhenRespEmpty(Collection<Variable> variables) {
        if (CollectionUtils.isEmpty(variables)) {
            return Collections.emptyMap();
        }
        return variables.stream().
                filter(Objects::nonNull).
                collect(Collectors.toMap(Variable::getVarCode, VariableHelper::getDefaultValue));
    }



    public static Map<String, Object> fillVarWithNullWhenFail(Collection<Variable> variables) {
        if (CollectionUtils.isEmpty(variables)) {
            return Collections.emptyMap();
        }
        return variables.stream().
                filter(Objects::nonNull).
                collect(Collectors.toMap(Variable::getVarCode, var -> "null"));
    }

}
